package com.cjlgb.design.common.core.util;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.util.StringUtils;

/**
 * @author WFT
 * @date 2019/5/18
 * description: Aop工具类
 */
public class AopUtil {

    private final static String DOT = ".";
    private final static String PIT = "#";

    /**
     * 根据El表达式，获取属性值
     * @param point 切入点
     * @param el Spring El表达式
     * @return 参数值
     */
    public static Object getAttributeByEl(ProceedingJoinPoint point, String el)throws Exception{
        //  判断表达式是否以#号开头
        if (el.length() > 0 && !el.startsWith(PIT)){
            return el;
        }
        //  去掉#号
        el = el.substring(1);
        //  获取参数名称
        int dotIndex = el.indexOf(DOT);
        if (dotIndex == 0 || dotIndex == el.length() - 1){
            throw new RuntimeException("El表达式语法错误:" + el);
        }
        MethodSignature signature = (MethodSignature)point.getSignature();
        //  参数名称列表
        String[] parameterNames = signature.getParameterNames();
        if (dotIndex == -1){
            //  获取对象的下表
            int objIndex = getIndexByName(el,parameterNames);
            return point.getArgs()[objIndex];
        }
        String name = el.substring(0,dotIndex);
        el = el.substring(dotIndex + 1);
        //  获取对象的下表
        int objIndex = getIndexByName(name,parameterNames);
        //  获取到参数对象
        Object obj = point.getArgs()[objIndex];
        //  递归对象的属性值
        return getAttributeByEl(obj, el);
    }

    /**
     * 根据El表达式,获取对象的属性值
     * @param obj 对象
     * @param el El表达式
     * @return Object
     * @throws Exception 反射异常
     */
    private static Object getAttributeByEl(Object obj,String el)throws Exception{
        if (StringUtils.isEmpty(el)){
            return obj;
        }
        int dotIndex = el.indexOf(DOT);
        //  判断是否还有下一级
        if (dotIndex == -1){
            //  获取属性值方法名称
            return ReflexUtil.getMethodName(el,obj.getClass()).invoke(obj);
        }
        //  获取属性名称
        String attributeName = el.substring(0,dotIndex);
        el = el.substring(dotIndex + 1);
        //  得到本级对象
        obj = ReflexUtil.getMethodName(attributeName,obj.getClass());
        //  继续递归
        return getAttributeByEl(obj,el);
    }

    /**
     * 从数组中找到对应的元素下标
     * @param name 元素
     * @param array 数组
     * @return 元素下表
     * @throws RuntimeException 如找不到将抛出异常
     */
    private static int getIndexByName(String name,String[] array)throws RuntimeException{
        for (int i = 0; i < array.length; i++) {
            String item = array[i];
            if (item.equals(name)){
                //  得到第一个参数
                return i;
            }
        }
        throw new RuntimeException("EL表达式语法错误,找不到参数：" + name);
    }

}
